package org.example.hypersonaltools.scene;

import javafx.animation.AnimationTimer;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import java.awt.event.FocusEvent;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class EStickyNoteScene extends Scene {
    private final Pane root;
    private final Stage stage;
    private boolean isCollapsed = false;
    private boolean isMousePressed = true;
    private Timer collapseTimer;
    private Region region;
    private Region title;
    private double xOffset;
    private double yOffset;
    private final Background backOne = new Background(new BackgroundFill(Color.color(1,1,1,0.7), CornerRadii.EMPTY, Insets.EMPTY));
    private final Background backTwo = new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY));
    private final Background backThree = new Background(new BackgroundFill(Color.color(1,1,1,0.7), CornerRadii.EMPTY, Insets.EMPTY));

    private final Font font=Font.font(14);;
    private final Font titleFont=Font.font(14);;
    private ContextMenu contextMenu;
    private ColorPalette colorPalette;
    private final TextField titleTextField=new TextField();

    public EStickyNoteScene(Pane root, Stage stage) {
        super(root, 380, 460);
        this.root = root;
        stage.initStyle(StageStyle.TRANSPARENT);
        this.stage = stage;
        this.setFill(null);//很重要步骤
        initializeUI();
        setupEventListeners();
        stage.setScene(this);
        stage.setAlwaysOnTop(true);
        stage.show();
    }

    private void initializeUI() {

        this.root.setStyle("-fx-background-color: transparent;");

        title = new Region();
        title.setMinHeight(40);
        title.setMinWidth(360);
        title.setLayoutY(50);
        title.setBackground(this.backThree);
        this.root.getChildren().add(title);
        //标题框
        titleTextField.setBackground(backTwo);
        titleTextField.setBorder(Border.EMPTY);
        titleTextField.setFont(titleFont);
        titleTextField.setLayoutY(55);
        titleTextField.setLayoutX(10);
        this.root.getChildren().add(titleTextField);

        region = new Region();
        region.setLayoutY(90);
        region.setMinHeight(320);
        region.setMinWidth(360);
        region.setBackground(this.backOne);
        this.root.getChildren().add(this.region);
        this.createContextMenu();

        colorPalette = new ColorPalette(
                Orientation.HORIZONTAL, 0, 0, 360, 50
        );

        colorPalette.setVisible(false);

        this.root.getChildren().add(colorPalette);
    }

    private void createContextMenu() {
        contextMenu = new ContextMenu();
        MenuItem newBuild = new MenuItem("新建");
        newBuild.setOnAction(actionEvent -> {
            new EStickyNoteScene(new Pane(), new Stage());
        });
        contextMenu.getItems().add(newBuild);
        contextMenu.focusedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
                if (!t1){
                    contextMenu.hide();
                }
            }
        });
    }

    private void setupEventListeners() {

        this.root.setOnMousePressed(mouseEvent -> {
            //阻止其他鼠标事件
            if (isMousePressed) {
                isMousePressed = false;
            }
        });

        this.root.setOnMouseReleased(mouseEvent -> {
            if (!isMousePressed) {
                isMousePressed = true;
            }
        });

        this.root.setOnMouseExited(mouseEvent -> {

            if (!isMousePressed) {
                return;
            }
            // 取消之前的计时器（如果存在）
            if (collapseTimer != null) {
                collapseTimer.cancel();
            }

            // 创建新的计时器
            collapseTimer = new Timer();
            collapseTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                        if (!isCollapsed) {
                            collapseStage();
                            colorPalette.setVisible(false);
                            //判断是否需要吸附到屏幕边缘并执行吸附动画
                            AdsorptionStage(stage.getX(),stage.getY(), Screen.getPrimary().getVisualBounds().getWidth());
                        }
                }
            }, 1000);

        });

        this.root.setOnMouseEntered(mouseEvent -> {
            // 鼠标进入时取消折叠计时
            if (collapseTimer != null) {
                collapseTimer.cancel();
            }

            // 如果已折叠，则展开
            if (isCollapsed) {
                expandStage();
            }
        });

        this.region.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getClickCount() == 2 && mouseEvent.getButton() == MouseButton.PRIMARY) {
                createFreeText(mouseEvent.getSceneX(), mouseEvent.getSceneY());
            }else if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 1){
                region.requestFocus();
            }
        });

        this.region.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
                for (Node child : root.getChildren()) {
                    if (child instanceof TextField){
                        if (child.getLayoutY()>=(t1.doubleValue()+region.getLayoutY())){
                            child.setOpacity(0);
                        }else {
                            child.setOpacity(1);
                        }
                    }
                }
            }
        });

        this.title.setOnMousePressed(event -> {
            // 记录鼠标按下时的位置偏移
            xOffset = event.getSceneX();
            yOffset = event.getSceneY();
        });

        this.title.setOnMouseDragged(event -> {
            // 根据鼠标移动更新窗口位置
            stage.setX(event.getScreenX() - xOffset);
            stage.setY(event.getScreenY() - yOffset);
        });

        this.title.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getEventType()== MouseEvent.MOUSE_CLICKED && mouseEvent.getButton().compareTo(MouseButton.SECONDARY)==0){
                //右键点击创建菜单栏
                contextMenu.show(stage,mouseEvent.getScreenX(),mouseEvent.getScreenY());
            }
            title.requestFocus();
        });

        titleTextField.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
                Text textNode = new Text(titleTextField.getText());
                textNode.setFont(font);
                double width = textNode.getLayoutBounds().getWidth();
                titleTextField.setMinWidth(width+21);
            }
        });

        this.root.setOnMouseClicked(mouseEvent -> {
            Node intersectedNode = mouseEvent.getPickResult().getIntersectedNode();
            if (intersectedNode instanceof Region){
                colorPalette.setVisible(true);
                colorPalette.setTargetRegion(List.of((Region) intersectedNode));
            }
        });
        this.titleTextField.focusedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
                if(t1){
                    colorPalette.setVisible(true);
                    colorPalette.setTargetRegion(List.of(titleTextField));
                }
            }
        });
    }

    private void AdsorptionStage(Double stageX, Double stageY, double width) {
        if (stageX<20){
            stage.setX(0);
        }else if ((stageX+stage.getWidth())>(width-20)){
            stage.setX(width-stage.getWidth());
        }
    }

    private void createFreeText(double x, double y) {
        TextField textField = new TextField();
        textField.setLayoutX(x);
        textField.setLayoutY(y);
        textField.setBackground(backTwo);
        textField.setBorder(Border.EMPTY);
        textField.setFont(font);

        textField.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
                Text textNode = new Text(textField.getText());
                textNode.setFont(font);
                double width = textNode.getLayoutBounds().getWidth();
                textField.setMaxWidth(width+21);
                colorPalette.setVisible(true);
                colorPalette.setTargetRegion(List.of(textField));
            }
        });
        textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
                if (!t1){
                    if (textField.getText().isEmpty()){
                        root.getChildren().remove(textField);
                    }
                }
            }
        });
        this.root.getChildren().add(textField);
        textField.requestFocus();
    }

    private void collapseStage() {
        double startHeight = 320;
        double targetHeight = 0;
        double duration = 1.5; // 秒
        long startTime = System.nanoTime();

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                double elapsed = (now - startTime) / 1_000_000_000.0; // 转换为秒
                double progress = Math.min(elapsed / duration, 1.0); // 0.0 → 1.0
                double easedProgress = easeOutBounce(progress);
                // 线性插值计算当前高度
                double currentHeight = startHeight + (targetHeight - startHeight) * easedProgress;

                region.setMinHeight(currentHeight);

                if (progress >= 1.0) {
                    stop(); // 动画结束
                    isCollapsed = true;
                }
            }
        };
        timer.start();
    }

    private void expandStage() {
        double startHeight = 320;
        double targetHeight = 320; // 原始高度
        double duration = 0.3; // 动画持续时间（秒）
        long startTime = System.nanoTime();

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                double elapsed = (now - startTime) / 1_000_000_000.0; // 转换为秒
                double progress = Math.min(elapsed / duration, 1.0); // 0.0 → 1.0
                double easedProgress = linear(progress);
                // 线性插值计算当前高度
                double currentHeight = startHeight + (targetHeight - startHeight) * easedProgress;
                region.setMinHeight(currentHeight);

                if (progress >= 1.0) {
                    stop(); // 动画结束
                    isCollapsed = false;
                }
            }
        };
        timer.start();
    }

    // 线性插值（默认）
    private double linear(double progress) {
        return progress;
    }

    // 二次缓入（EaseIn）
    private double easeInQuad(double progress) {
        return progress * progress;
    }

    // 二次缓出（EaseOut）
    private double easeOutQuad(double progress) {
        return 1 - (1 - progress) * (1 - progress);
    }

    // 二次缓入缓出（EaseInOut）
    private double easeInOutQuad(double progress) {
        return progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
    }

    // 弹性效果（Elastic）
    private double easeOutElastic(double progress) {
        if (progress == 0) return 0;
        if (progress == 1) return 1;
        return Math.pow(2, -10 * progress) * Math.sin((progress * 10 - 0.75) * (2 * Math.PI) / 3) + 1;
    }

    // 弹跳效果（Bounce）
    private double easeOutBounce(double progress) {
        if (progress < (1 / 2.75)) {
            return 7.5625 * progress * progress;
        } else if (progress < (2 / 2.75)) {
            return 7.5625 * (progress -= (1.5 / 2.75)) * progress + 0.75;
        } else if (progress < (2.5 / 2.75)) {
            return 7.5625 * (progress -= (2.25 / 2.75)) * progress + 0.9375;
        } else {
            return 7.5625 * (progress -= (2.625 / 2.75)) * progress + 0.984375;
        }
    }
}